package com.example.dishit.service.recommendation;

import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutionException;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;

import com.example.dishit.application.DishApplication;
import com.example.dishit.model.dish.DishData;

public class LocationService {

	private static final String PLACES_API_BASE = "https://maps.googleapis.com/maps/api/place/nearbysearch/json";
	
	private static final String PLACES_API_DETAILS_BASE = "https://maps.googleapis.com/maps/api/place/details/json";

	private static final String API_KEY = "AIzaSyAR3UgiSOfnUaDb-eNFMJ7L4htNK10lptg";

	double latitude = 0.0;
	double longitude = 0.0;
	ArrayList<DishData> resultList = null;
	DishData dishData = null;
	private long radiusMeters;

	public ArrayList<DishData> getNearbyRestaurants() {
	    return getNearbyRestaurants(10000);
	}
	
	public ArrayList<DishData> getNearbyRestaurants(final long rMeters) {
	    this.radiusMeters = rMeters;
	    
		final LocationManager locManager = (LocationManager) DishApplication
				.getAppContext().getSystemService(Context.LOCATION_SERVICE);

		Handler mHandler = new Handler(Looper.getMainLooper());
		mHandler.post(new Runnable() {
			public void run() {
				locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
						1000L, 500.0f, locationListener);
			}
		});

		Location location = locManager
				.getLastKnownLocation(LocationManager.GPS_PROVIDER);
		if (location != null) {
			latitude = location.getLatitude();
			longitude = location.getLongitude();
		}

		AsyncTask task = new CallGoogleApiTask().execute(null, null, null);
		try {
			task.get();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return resultList;
	}

	public DishData getRestaurantDetails(final String reference) {
	    AsyncTask task = new CallGoogleApiTaskForDetails().execute(reference, null, null);
		try {
			task.get();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return dishData;
	}
	
	private final LocationListener locationListener = new LocationListener() {
		public void onLocationChanged(Location location) {
			updateWithNewLocation(location);
		}

		public void onProviderDisabled(String provider) {
			updateWithNewLocation(null);
		}

		public void onProviderEnabled(String provider) {
		}

		public void onStatusChanged(String provider, int status, Bundle extras) {
		}
	};

	private void updateWithNewLocation(Location location) {
		if (location != null) {
			latitude = location.getLatitude();
			longitude = location.getLongitude();
		}
	}

	private class CallGoogleApiTask extends AsyncTask<URL, Integer, Long> {
		protected Long doInBackground(URL... urls) {
			long totalSize = 0;
			HttpURLConnection conn = null;

			StringBuilder jsonResults = new StringBuilder();
			try {
				StringBuilder sb = new StringBuilder(PLACES_API_BASE);
				sb.append("?sensor=false&key=" + API_KEY);
				if (latitude == 0.0 || longitude == 0.0) {// Set default
															// location
					latitude = 29.6514;
					longitude = -82.3250;
				}

				sb.append("&location=" + latitude + "," + longitude
						+ "&radius=" + radiusMeters + "&sensor=false&types=restaurant");
				URL url = new URL(sb.toString());
				conn = (HttpURLConnection) url.openConnection();
				InputStreamReader in = new InputStreamReader(
						conn.getInputStream());

				// Load the results into a StringBuilder
				int read;
				char[] buff = new char[1024];
				while ((read = in.read(buff)) != -1) {
					jsonResults.append(buff, 0, read);
				}
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				if (conn != null) {
					conn.disconnect();
				}
			}

			try {
				// Create a JSON object hierarchy from the results
				JSONObject jsonObj = new JSONObject(jsonResults.toString());
				JSONArray predsJsonArray = jsonObj.getJSONArray("results");

				// Extract the Place descriptions from the results
				resultList = new ArrayList<DishData>(
						predsJsonArray.length());
				for (int i = 0; i < predsJsonArray.length(); i++) {
					String name = predsJsonArray.getJSONObject(i).getString(
							"name");
					String description = predsJsonArray.getJSONObject(i)
							.getString("vicinity");
					String reference = predsJsonArray.getJSONObject(i)
							.getString("reference");
					int priceLevel = 1;
					if (predsJsonArray.getJSONObject(i).has("price_level")) {
						priceLevel = predsJsonArray.getJSONObject(i)
								.getInt("price_level");
					}					
					float minPrice = priceLevel*2 + 0.02f*(new Random().nextInt(100));
					float maxPrice = priceLevel*8 + 0.02f*(new Random().nextInt(100));
					//minPrice = Math.round(minPrice*100);
					//minPrice = minPrice/100;
					//maxPrice = (Math.round(maxPrice*100))/100;
					Float rating;
					try {
					    rating = Float.valueOf(predsJsonArray
					            .getJSONObject(i).getString("rating"));
					} catch (JSONException e) {
					    // FIXME; hack; just fill in something
					    rating = 4.2f;
		                e.printStackTrace();
		                // Log.e(LOG_TAG, "Cannot process JSON results", e);
		            }
					
					
					
					JSONArray photos = null;
					List<String> imageUrls = new ArrayList<String>();
					if (predsJsonArray.getJSONObject(i).has("photos")) {
						photos = predsJsonArray.getJSONObject(i).getJSONArray(
								"photos");
						for (int j = 0; j < photos.length(); j++) {
							String photoRef = photos.getJSONObject(j).getString(
									"photo_reference");
							String imageURL = "https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference="+photoRef+"&sensor=true&key="+API_KEY; 
							imageUrls.add(imageURL);//TODO update this
							
						}
					}

   				    // FIXME: hack; we only want restaurants with photos
					if(imageUrls.isEmpty()) continue;
						
					resultList.add(new DishData.Builder()
							.restaurantName(name).streetAddress(description).reference(reference).priceMin(minPrice).priceMax(maxPrice)
							.imageUrls(imageUrls).rating(rating)
							.recommendedBy("DishIt").build());
				}
			} catch (JSONException e) {
				e.printStackTrace();
				// Log.e(LOG_TAG, "Cannot process JSON results", e);
			}

			return totalSize;
		}

	}
	

	private class CallGoogleApiTaskForDetails extends AsyncTask<String, Integer, Long> {
		@Override
		protected Long doInBackground(String... reference) {
			long totalSize = 0;
			HttpURLConnection conn = null;

			StringBuilder jsonResults = new StringBuilder();
			try {
				StringBuilder sb = new StringBuilder(PLACES_API_DETAILS_BASE);
				sb.append("?reference=" + reference[0]);
				sb.append("&sensor=true&key=" + API_KEY);
				
				URL url = new URL(sb.toString());
				conn = (HttpURLConnection) url.openConnection();
				InputStreamReader in = new InputStreamReader(
						conn.getInputStream());

				// Load the results into a StringBuilder
				int read;
				char[] buff = new char[1024];
				while ((read = in.read(buff)) != -1) {
					jsonResults.append(buff, 0, read);
				}
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				if (conn != null) {
					conn.disconnect();
				}
			}

			try {
				// Create a JSON object hierarchy from the results
				JSONObject jsonObj = new JSONObject(jsonResults.toString());
				JSONObject resultObj = jsonObj.getJSONObject("result");
				JSONArray addressComponents = resultObj.getJSONArray("address_components");
				JSONArray keywords = resultObj.getJSONArray("types");
				
				List<String> keywordsList = new ArrayList<String>();
				List<String> reasonsList = new ArrayList<String>();
				List<String> commentsList = new ArrayList<String>();
				for (int i=0; i<keywords.length(); i++) {
				    final String keyword = keywords.getString(i);
					keywordsList.add(keyword);
					reasonsList.add("you like " + keyword + "s");
					
					// FIXME:  hack; to get comments working.
					if(i == 0) 
					    commentsList.add("Evan:    The " + keyword + " is incredible here!");
					else if(i == 1)
					    commentsList.add("Charan:    The " + keyword + " is alright, but I'd call ahead.");
					else if(i == 2)
					    commentsList.add("Paramjit:    You will definitely like the  " + keyword + ".");
					    
				}
				String phone = resultObj.getString("formatted_phone_number");
				String websiteUrl = resultObj.getString("website");
				String streetNum = null;
				String streetAdd = null;
				String city = null;
				String state = null;
				String zip = null;
				
				
				for (int i = 0; i < addressComponents.length(); i++) {
					JSONObject obj = (JSONObject) addressComponents.get(i);
					JSONArray types = (JSONArray) obj.get("types");
					String val = obj.getString("long_name");
					if (types.getString(0).equalsIgnoreCase("street_number")){
						streetNum = val;
					} else if (types.getString(0).equalsIgnoreCase("route")){
						streetAdd = val;
					} else if (types.getString(0).equalsIgnoreCase("locality")){
						city = val;
					} else if (types.getString(0).equalsIgnoreCase("administrative_area_level_1")){
						state = val;
					} else if (types.getString(0).equalsIgnoreCase("postal_code")){
						zip = val;
					} 
					
					//System.out.println(obj1.toString() + val);
				}
				dishData = new DishData.Builder().phoneNumberDigits(phone).websiteUrl(websiteUrl)
				                .keywords(keywordsList)
				                .reasons(reasonsList)
				                .comments(commentsList)
				.streetAddress(streetNum + " " + streetAdd).city(city).state(state).zipcode(zip).build();
				
				// Extract the Place descriptions from the results
				/*resultList = new ArrayList<DishData>(
						predsJsonArray.length());
				for (int i = 0; i < predsJsonArray.length(); i++) {
					String name = predsJsonArray.getJSONObject(i).getString(
							"name");
					String description = predsJsonArray.getJSONObject(i)
							.getString("vicinity");
					String reference = predsJsonArray.getJSONObject(i)
							.getString("reference");
					Float rating = Float.valueOf(predsJsonArray
							.getJSONObject(i).getString("rating"));
					JSONArray photos = null;
					List<String> imageUrls = new ArrayList<String>();
					if (predsJsonArray.getJSONObject(i).has("photos")) {
						photos = predsJsonArray.getJSONObject(i).getJSONArray(
								"photos");
						for (int j = 0; j < photos.length(); j++) {
							imageUrls.add(photos.getJSONObject(j).getString(
									"photo_reference"));
						}
					}

					resultList.add(new DishData.Builder()
							.restaurantName(name).streetAddress(description).reference(reference)
							.imageUrls(imageUrls).rating(rating).build());
				}*/
			} catch (JSONException e) {
				e.printStackTrace();
				// Log.e(LOG_TAG, "Cannot process JSON results", e);
			}

			return 1l;
		}

	}


}
